// File LocationMachine.cpp
//
// Purpose: Contains the machine for monitoring locations
//
// Author : Bryson King (edited)
// Original Code Provided by: Mat Buckland 2002 (fup@ai-junkie.com)
// Date : 18 March 2013
// --------------------------------------------------------------
#define DEBUG_SECTION

#include "LocationMachine.h"

#include <string>

#include "AbstractLocation.h"
#include "Telegram.h"
#include "UserInterface.h"
#include "IPerson.h"

class IPerson;
class CLocation;

CLocationMachine::CLocationMachine(IPerson* owner):m_pOwner(owner),
								m_pCurrentLocation(nullptr),
								m_pPreviousLocation(nullptr),
								m_mLocationsVisited()
{}
CLocationMachine::~CLocationMachine(){}

void CLocationMachine::SetCurrentLocation(CLocation* s)
{
	m_pCurrentLocation = s;

	// Add location to locations visited if not already there
	m_mLocationsVisited[s] = true;
}
void CLocationMachine::SetPreviousLocation(CLocation* s)
{
	m_pPreviousLocation = s;
}
  
//call this to update the location machine
void CLocationMachine::Update() const
{
	//call execute function for current location
	if (m_pCurrentLocation)
		m_pCurrentLocation->Execute(m_pOwner);
}

bool CLocationMachine::HandleMessage(const Telegram& msg)const
{
	//first see if the current location is valid and that it can handle
	//the message
	if (m_pCurrentLocation && m_pCurrentLocation->OnMessage(m_pOwner, msg))
	{
		return true;
	}
  
	return false;
}

//change to a new location
void CLocationMachine::ChangeLocation(CLocation* pNewLocation)
{
	#ifdef DEBUG_SECTION
	//make sure the val is equal to or greater than the next available ID
		if(!(pNewLocation))
			std::cout << std::endl << "<CPlayerStateMachine::ChangeLocation>:trying to assign null location to current";
	#endif

	//keep a record of the previous location
	m_pPreviousLocation = m_pCurrentLocation;

	//call the exit method of the existing location
	m_pCurrentLocation->Exit(m_pOwner);

	//change location to the new location
	m_pCurrentLocation = pNewLocation;

	//call the entry method of the new location
	m_pCurrentLocation->Enter(m_pOwner);

	// Add new location to the map of locations visited
	m_mLocationsVisited[pNewLocation] = true;
}

//returns true if the current location's type is equal to the type of the
//class passed as a parameter. 
bool CLocationMachine::isInLocation(const CLocation& loc) const
{
	if (typeid(*m_pCurrentLocation) == typeid(loc)) 
		return true;
	return false;
}

CLocation* CLocationMachine::CurrentLocation()  const
{
	return m_pCurrentLocation;
}
CLocation* CLocationMachine::PreviousLocation() const
{
	return m_pPreviousLocation;
}

//only ever used during debugging to grab the name of the current location
std::string CLocationMachine::GetNameOfCurrentLocation() const
{
	std::string s(typeid(*m_pCurrentLocation).name());

	//remove the 'class ' part from the front of the string
	if (s.size() > 5)
	{
		s.erase(0, 6);
	}

	return s;
}

bool CLocationMachine::LocationVisitedAlready(CLocation* LocationToCheck) const
{
	map<CLocation*, bool>::const_iterator l_checkIfVisited;

	l_checkIfVisited = m_mLocationsVisited.find(LocationToCheck);

	// If the location is in the map, it has been visited, otherwise it has not
	if (l_checkIfVisited == m_mLocationsVisited.end())
		return false;
	else
		return true;
}
